import { h, defineComponent, markRaw, ref, watch, onUnmounted } from 'vue'
import ItemNode from '../../ItemNode/ItemNode'
import {
  ElButton,
  ElForm,
  ElFormItem,
  ElIcon,
  ElInput,
  ElInputNumber,
  ElPagination,
  ElPopover,
  ElSwitch,
  ElText,
  ElTree
} from 'element-plus'
import classes from '../../ItemNode/ItemNode.module.css'
import TableVue from './TableVue.vue'
import TableVueRaw from './TableVue.vue?raw'
import TableColumnRaw from './TableColumn.vue?raw'
import exportExcel from './exportExcel'
import exportExcelRaw from './exportExcel?raw'
import { debounce } from '../../utils'
import request from '../../request/request'
import requestRaw from '../../request/request?raw'
import { state } from '../../store/store.js'
import { Delete, Edit, Plus } from '@element-plus/icons-vue'
import CodeEditor from '../../panel/CodeEditor.vue'
import Tip from '../../panel/Tip.vue'

export default class NTable extends ItemNode {
  isNTable = true
  isDataDisplayNode = true

  constructor(node?: NTable) {
    super(node)

    this.watchStateOptions.push({
      value: 'initData',
      label: '刷新数据'
    })

    if (!node) {
      this.path = './components/NTable/NTable.tsx'
      this.name = '表格'

      const style = this.props.style
      this.props.style = {
        ...style,
        flexShrink: '0'
      }

      this.props.dataUrl = ''
      this.props.dataFn =
        'function (res) {\n  return [{\n    defaultA: String,\n    defaultC: String,\n    defaultD: String\n  }]\n}'
      this.props.totalFn = 'function (res) {\n  return Number\n}'

      this.props.height = 150
      this.props.exportExcel = false
      this.props.pagination = false
      this.props.transparent = false
      this.props.autoScroll = false
      // 最下面的数据列不能有children属性
      this.props.columns = [
        { id: Math.random(), title: 'defaultA', dataIndex: 'defaultA' },
        {
          id: Math.random(),
          title: 'defaultB',
          children: [
            {
              id: Math.random(),
              title: 'defaultC',
              dataIndex: 'defaultC',
              sortable: true,
              showOverflowTooltip: true
            },
            { id: Math.random(), title: 'defaultD', dataIndex: 'defaultD' }
          ]
        }
      ]
    }

    const pComponent = this.component
    this.component = markRaw(
      defineComponent(
        (props) => {
          let data = ref([
            { id: Math.random(), defaultA: 'defaultA', defaultC: 'defaultC', defaultD: 'defaultD' },
            { id: Math.random(), defaultA: 'defaultA', defaultC: 'defaultC', defaultD: 'defaultD' }
          ])
          let currentPage = ref(1)
          let pageSize = ref(10)
          let total = ref(0)
          const search = ref('')

          // 导出excel
          const handleExportExcel = async () => {
            await request({
              url: this.props.dataUrl,
              method: 'GET'
            }).then((res) => {
              if (this.props.dataFn) {
                if (state) exportExcel(this.props.columns, eval(`(${this.props.dataFn})`)(res))
              }
            })
          }

          const initData = async () => {
            if (!this.props.dataUrl) return

            data.value = []

            const query: any = this.props.pagination
              ? {
                  currentPage: currentPage.value,
                  pageSize: pageSize.value
                }
              : {}

            await request({
              url:
                this.props.dataUrl.replace(/\:(\w+)/g, (match, p1) => state[p1]) +
                `${this.props.dataUrl.includes('?') ? '&' : '?'}${new URLSearchParams(query)}`,
              method: 'GET'
            }).then((res) => {
              if (!state) return

              if (this.props.dataFn) {
                try {
                  const resData = eval(`(${this.props.dataFn})`)(res)
                  if (Array.isArray(resData)) data.value = resData
                } catch (e) {}
              }
              if (this.props.totalFn) {
                try {
                  const resTotal = eval(`(${this.props.totalFn})`)(res)
                  total.value = resTotal
                } catch (e) {}
              }
            })
          }

          const handlePaginationChange = (currentP, pSize) => {
            currentPage.value = currentP
            pageSize.value = pSize

            initData()
          }

          // 控制监听频率
          const initDataDebounce = debounce(() => {
            initData()
          }, 1000)

          watch(
            [
              () => this.props.dataUrl,
              () => this.props.dataFn,
              () => this.props.totalFn,
              () => this.props.pagination
            ],
            initDataDebounce
          )

          initDataDebounce()
          // 解除监听state属性的函数集合
          const watchStateSet = new Set()
          // 监听依赖的state属性，响应对应方法
          watch(
            () => this.props.watchState,
            () => {
              watchStateSet.forEach((v: () => void) => v())

              this.props.watchState.forEach((watchObj: watchStateObj) => {
                if (watchObj.type == 'initData') {
                  watchStateSet.add(watch(() => state[watchObj.stateProperty], initData))
                }
              })
            },
            { immediate: true, deep: true }
          )

          onUnmounted(() => {
            watchStateSet.forEach((v: () => void) => v())
          })

          return () => (
            <pComponent>
              <div
                style={{
                  display: 'flex',
                  'justify-content': 'flex-end'
                }}
              >
                {[
                  this.props.exportExcel && (
                    <ElButton onClick={handleExportExcel}>导出excel</ElButton>
                  )
                ]}
              </div>
              <TableVue
                height={this.props.height}
                columns={this.props.columns}
                data={data.value}
                transparent={this.props.transparent}
                autoScroll={this.props.autoScroll}
              ></TableVue>
              {this.props.pagination && (
                <ElPagination
                  layout="total, sizes, prev, pager, next, jumper"
                  total={total.value}
                  page-sizes={[10, 20, 30, 40, 50, 100]}
                  style={{ marginTop: '10px' }}
                  size="small"
                  background
                  onChange={handlePaginationChange}
                ></ElPagination>
              )}
            </pComponent>
          )
        },
        {
          name: 'NTable'
        }
      )
    )

    const pView = this.view
    this.view = markRaw(
      defineComponent((props) => {
        return () => (
          <pView>
            <this.component style={{ transform: 'scale(0.35, 0.25)' }}></this.component>
          </pView>
        )
      })
    )

    const pParams = this.params
    this.params = markRaw(
      defineComponent(() => {
        return () => (
          <pParams>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                数据url
                <Tip content={'可引用全局状态变量state的属性，例子：/abc/:def引用state.def'}></Tip>
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput
                  modelValue={this.props.dataUrl}
                  onUpdate:modelValue={(v) => (this.props.dataUrl = v || '')}
                  size="small"
                ></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                接口数据处理函数
                <Tip
                  content={'接口url不为空时启用；可访问全局状态变量state，res：接口返回数据'}
                ></Tip>
              </ElText>
              <div class={classes['params-item-content']}>
                <CodeEditor
                  modelValue={this.props.dataFn}
                  onUpdate:modelValue={(v) => (this.props.dataFn = v || '')}
                ></CodeEditor>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                表格高度
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInputNumber v-model={this.props.height} min={0} size="small"></ElInputNumber>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                分页
                <Tip content={'分页需设置：分页总数处理函数'}></Tip>
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSwitch
                  modelValue={this.props.pagination}
                  onUpdate:modelValue={(v) => (this.props.pagination = v)}
                  size="small"
                ></ElSwitch>
              </div>
            </div>
            {this.props.pagination && (
              <div class={classes['params-item']}>
                <ElText class={classes['params-item-label']} type="info">
                  接口数据处理函数
                  <Tip
                    content={'接口url不为空时启用；可访问全局状态变量state，res：接口返回数据'}
                  ></Tip>
                </ElText>
                <div class={classes['params-item-content']}>
                  <CodeEditor
                    modelValue={this.props.totalFn}
                    onUpdate:modelValue={(v) => (this.props.totalFn = v || '')}
                  ></CodeEditor>
                </div>
              </div>
            )}
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                表头
              </ElText>
              <div class={classes['params-item-content']}>
                <ElButton
                  type="primary"
                  size="small"
                  onClick={() => {
                    const newChild = {
                      id: Math.random(),
                      title: '',
                      dataIndex: ''
                    }
                    this.props.columns.push(newChild)
                  }}
                >
                  + 添加列
                </ElButton>
                <ElTree
                  data={this.props.columns}
                  node-key="id"
                  default-expand-all
                  expand-on-click-node={false}
                >
                  {{
                    default: ({ node, data }) => {
                      return (
                        <span
                          style={{
                            flex: '1',
                            display: 'flex',
                            justifyContent: 'space-between'
                          }}
                        >
                          <span>{data.title}</span>
                          <span>
                            <ElPopover
                              width={180}
                              trigger="click"
                              teleported={false}
                              placement="left"
                            >
                              {{
                                reference: () => (
                                  <ElIcon color="var(--el-color-primary)">
                                    <Edit></Edit>
                                  </ElIcon>
                                ),
                                default: () => {
                                  return (
                                    <>
                                      <ElForm label-width="80px">
                                        <ElFormItem label="标题">
                                          <ElInput v-model={data.title}></ElInput>
                                        </ElFormItem>
                                        <ElFormItem label="字段">
                                          <ElInput v-model={data.dataIndex}></ElInput>
                                        </ElFormItem>
                                        <ElFormItem label="排序">
                                          <ElSwitch
                                            modelValue={data.sortable}
                                            onUpdate:modelValue={(v) => (data.sortable = v)}
                                          ></ElSwitch>
                                        </ElFormItem>
                                        <ElFormItem label="提示信息">
                                          <ElSwitch v-model={data.showOverflowTooltip}></ElSwitch>
                                        </ElFormItem>
                                      </ElForm>
                                    </>
                                  )
                                }
                              }}
                            </ElPopover>
                            {h(
                              ElIcon,
                              {
                                color: 'var(--el-color-warning)',
                                onClick: () => {
                                  const newChild = {
                                    id: Math.random(),
                                    title: '',
                                    dataIndex: ''
                                  }
                                  if (!data.children) data.children = []
                                  data.children.push(newChild)
                                  this.props.columns = [...this.props.columns]
                                }
                              },
                              {
                                default: () => <Plus></Plus>
                              }
                            )}
                            {h(
                              ElIcon,
                              {
                                color: 'var(--el-color-danger)',
                                onClick: () => {
                                  const parent = node.parent
                                  const children = parent.data.children || parent.data
                                  const index = children.findIndex(
                                    (d) => d.dataIndex === data.dataIndex
                                  )
                                  children.splice(index, 1)
                                }
                              },
                              {
                                default: () => <Delete></Delete>
                              }
                            )}
                          </span>
                        </span>
                      )
                    }
                  }}
                </ElTree>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                导出excel
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSwitch
                  modelValue={this.props.exportExcel}
                  onUpdate:modelValue={(v) => (this.props.exportExcel = v)}
                  size="small"
                ></ElSwitch>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                背景透明
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSwitch v-model={this.props.transparent} size="small"></ElSwitch>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                自动滚动
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSwitch v-model={this.props.autoScroll} size="small"></ElSwitch>
              </div>
            </div>
          </pParams>
        )
      })
    )
  }

  toVue(): SfcObj {
    const sfcObj = super.toVue()
    const name = sfcObj.name
    const [uuid0, uuid1] = this.uuid.split('-')
    const columnsVar = `${name}_${uuid0}_columns`
    const dataVar = `${name}_${uuid0}_data`
    const handleExportExcelVar = `${name}_${uuid0}_handleExportExcel`
    const currentPageVar = `${name}_${uuid0}_currentPage`
    const pageSizeVar = `${name}_${uuid0}_pageSize`
    const handlePaginationChangeVar = `${name}_${uuid0}_handlePaginationChang`
    const totalVar = `${name}_${uuid0}_total`
    const initDataVar = `${name}_${uuid0}_initData`

    const columnsStr = JSON.stringify(this.props.columns)

    sfcObj.imports = {
      ...sfcObj.imports,
      vue: {
        ref: 'ref',
        watch: 'watch'
      },
      ['element-plus']: {
        ElButton: 'ElButton',
        ElInput: 'ElInput',
        ElPagination: 'ElPagination'
      },
      ['./imports/TableVue.vue']: {
        default: 'TableVue'
      },
      ['./imports/exportExcel.js']: {
        default: 'exportExcel'
      },
      ['./imports/request.js']: {
        default: 'request'
      }
    }

    sfcObj.importFiles = {
      ...sfcObj.importFiles,
      'TableVue.vue': TableVueRaw,
      'TableColumn.vue': TableColumnRaw,
      'exportExcel.js': exportExcelRaw,
      'request.js': requestRaw
    }

    sfcObj.script = `
${sfcObj.script}
const ${columnsVar} = ref(${columnsStr})
const ${dataVar} = ref([])
${
  this.props.pagination
    ? `
const ${totalVar} = ref(0)
const ${currentPageVar} = ref(1)
const ${pageSizeVar} = ref(10)
const ${handlePaginationChangeVar} = (currentP, pSize) => {
  ${currentPageVar}.value = currentP
  ${pageSizeVar}.value = pSize

  ${initDataVar}()
}
`
    : ''
}
${
  this.props.exportExcel
    ? `const ${handleExportExcelVar} = async () => {
  await request({
    url: '${this.props.dataUrl}',
    method: 'GET'
  }).then((res) => {
    ${this.props.dataFn ? `exportExcel(${columnsVar}.value, (${this.props.dataFn})(res))` : ''}
  })
}
`
    : ''
} 
const ${initDataVar} = async () => {
  ${dataVar}.value = []

  const query = ${
    this.props.pagination
      ? `{
    currentPage: ${currentPageVar}.value,
    pageSize: ${pageSizeVar}.value
  }`
      : `{}`
  }

  await request({
    url: '${this.props.dataUrl}'.replace(/\\:(\\w+)/g, (match, p1) => state[p1]) + \`${this.props.dataUrl.includes('?') ? '&' : '?'}\${new URLSearchParams(query)}\`,
    method: 'GET'
  }).then((res) => {
    ${dataVar}.value = (${this.props.dataFn || '() => []'})(res)
    ${
      this.props.pagination && this.props.totalFn
        ? `${totalVar}.value = (${this.props.totalFn})(res)`
        : ''
    }
  })
}
  
${initDataVar}()
${
  this.props.watchState.length > 0
    ? `
${this.props.watchState
  .map((obj) => {
    if (obj.type == 'initData') return `watch(() => state.${obj.stateProperty}, ${initDataVar})`
  })
  .join('\n')}
    `
    : ''
}
      `

    sfcObj.template = sfcObj.template.replace(
      '<slot></slot>',
      `
  ${
    this.props.exportExcel
      ? `
  <ElButton @click="${handleExportExcelVar}">导出excel</ElButton>
      `
      : ''
  }
  <TableVue
    :height="${typeof this.props.height == 'string' ? `'${this.props.height}'` : this.props.height}"
    :columns="${columnsVar}"
    :data="${dataVar}"
    :transparent="${this.props.transparent}"
    :autoScroll="${this.props.autoScroll}"
  ></TableVue>
${
  this.props.pagination
    ? `
  <ElPagination
    layout="total, sizes, prev, pager, next, jumper"
    :total="${totalVar}"
    :page-sizes="[10, 20, 30, 40, 50, 100]"
    :style="{ marginTop: '10px' }"
    size="small"
    background
    @change="${handlePaginationChangeVar}"
  ></ElPagination>`
    : ''
}
      `
    )

    return sfcObj
  }
}
